
package com.trydofor.id.xnet;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import com.trydofor.id.body.shell.ShellQueryBody;

/**
 * build the config
 * 
 * @author : Shi Rongjiu (www.trydofor.com)
 */
public final class ConfBuilder {
    
    private ConfBuilder() {
        
    }
    
    /**
     * build default config
     * 
     * @return the config
     */
    public static Config buildDefault() {
        Config cnf = new Config();
        for (InetAddress adr : getInetAddress()) {
            cnf.addBindHost(new InetSocketAddress(adr, Constant.SERVICE_PORT));
        }
        return cnf;
    }
    
    /**
     * build a configuration from the xml InputStream
     * and close the stream finally
     * 
     * @param input the xml
     * @return the config
     * @throws Exception if an error occurs during parsing.
     */
    public static Config buildCnf(InputStream input) throws Exception {
        Config cnf = new Config();
        try {
            SAXReader sax = new SAXReader();
            Document doc = sax.read(input);
            
            // ware
            Node w = doc.selectSingleNode("/a9id/conf/ware");
            if (w != null) {
                cnf.setWare(w.getText());
            }
            
            // bindhost
            List<?> bds = doc.selectNodes("/a9id/conf/bind/host");
            if (bds != null && !bds.isEmpty()) {
                for (Object obj : bds) {
                    Node nd = (Node) obj;
                    int port = Integer.parseInt(nd.valueOf("@port"));
                    cnf.addBindHost(new InetSocketAddress(nd.getText(), port));
                }
            }
            
            // command
            List<?> nds = doc.selectNodes("/a9id/init/cmd");
            if (nds != null && !nds.isEmpty()) {
                for (Object obj : nds) {
                    Node nd = (Node) obj;
                    ShellQueryBody cmd = new ShellQueryBody(nd.valueOf("@name"));
                    for (Object o : nd.selectNodes("arg")) {
                        Node n = (Node) o;
                        cmd.addArgument(n.valueOf("@name"), n.getText());
                    }
                    cnf.addCommand(cmd);
                }
            }
        }
        finally {
            if (input != null) input.close();
        }
        return cnf;
    }
    
    /**
     * build commands from the xml InputStream
     * and close the stream finally
     * 
     * @param input the xml
     * @return the config
     * @throws Exception if an error occurs during parsing.
     */
    public static List<ShellQueryBody> buildCmd(InputStream input) throws Exception {
        List<ShellQueryBody> cmds = new ArrayList<ShellQueryBody>();
        try {
            SAXReader sax = new SAXReader();
            Document doc = sax.read(input);
            
            // command
            List<?> nds = doc.selectNodes("//cmd");
            if (nds != null && !nds.isEmpty()) {
                for (Object obj : nds) {
                    Node nd = (Node) obj;
                    ShellQueryBody cmd = new ShellQueryBody(nd.valueOf("@name"));
                    for (Object o : nd.selectNodes("arg")) {
                        Node n = (Node) o;
                        cmd.addArgument(n.valueOf("@name"), n.getText());
                    }
                    cmds.add(cmd);
                }
            }
        }
        finally {
            if (input != null) input.close();
        }
        
        return cmds;
    }
    
    /**
     * get all local ip addresses
     * 
     * @return the addresses
     */
    public static List<InetAddress> getInetAddress() {
        List<InetAddress> addr = new ArrayList<InetAddress>();
        try {
            String name = InetAddress.getLocalHost().getHostName();
            for (InetAddress ia : InetAddress.getAllByName(name)) {
                addr.add(ia);
            }
        }
        catch (UnknownHostException e) {
            // ignore
        }
        
        return addr;
    }
    
    /**
     * load the stream from (1)classpath (2)system or null
     * 
     * @param path the config path
     * @return an input stream for reading the resource, or null if the resource could not be found
     */
    public static InputStream loadStream(String path) {
        InputStream ins = ClassLoader.getSystemResourceAsStream(path);
        if (ins == null) {
            try {
                ins = new FileInputStream(path);
            }
            catch (FileNotFoundException e) {
                ins = null;
            }
        }
        
        try {
            if (ins != null && ins.available() <= 0) {
                ins = null;
            }
        }
        catch (Exception e) {
            ins = null;
        }
        
        return ins;
    }
    
    /**
     * stream to byte array and close the stream
     * 
     * @param input the input stream
     * @return the bytes
     */
    public static byte[] streamToBytes(InputStream input) {
        byte[] result = new byte[0];
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int i = input.read(buf);
            while (i > 0) {
                bos.write(buf, 0, i);
                i = input.read(buf);
            }
            result = bos.toByteArray();
        }
        catch (IOException e) {
            // ignore
        }
        finally {
            try {
                if (input != null) {
                    input.close();
                }
            }
            catch (IOException e1) {
                // ignore
            }
        }
        return result;
    }
}
